﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using Microsoft.Xna.Framework;
using Isis;
namespace IsisCubeDemo
{
    //Msg TID = 0
    [AutoMarshalled]
    public class DemoObjectState
    {
        public DemoObjectState()
        {
        }
        
        public DemoObjectState(Vector3 position, Vector3 direction, Vector3 color, int number, int id)
        {
            this.id = id;
            this.positionX = position.X;
            this.positionY = position.Y;
            this.positionZ = position.Z;
            this.directionX = direction.X;
            this.directionY = direction.Y;
            this.directionZ = direction.Z;
            this.colorR = color.X;
            this.colorG = color.Y;
            this.colorB = color.Z;
            this.number = number;
        }
        public Ball makeBallFromState()
        {
            return new Ball(new Vector3(positionX, positionY, positionZ),
                            new Vector3(directionX, directionY, directionZ),
                            new Vector3(colorR, colorG, colorB), number, id);
        }
        public Cube makeCubeFromState()
        {
            return new Cube(new Vector3(positionX, positionY, positionZ),

                            new Vector3(colorR, colorG, colorB), number, id);
        }
        public int id;
        public float positionX;
        public float positionY;
        public float positionZ;
        public float directionX;
        public float directionY;
        public float directionZ;
        public float colorR;
        public float colorG;
        public float colorB;
        public int number;
    }
    
    public delegate void setBallState_T(Msg msg);
    public delegate void createBall_T(Msg msg);
    public delegate void setCubeState_T(Msg msg);
    public class IsisNode :GameComponent
    {
        
        public View view;
        private Thread thread;
        public Group group;
        SceneManager sceneManager;
        public Object sceneStateLock = new Object();
        public bool stateMsgRcvd = true;
        public static int maxBallNumber = 10000;
        public static int maxCubeNumber = 1000;
        public IsisNode(Game game)
            : base(game)
        {
            
        }
        public override void Initialize()
        {
            sceneManager = (SceneManager)Game.Components.First(c => c.GetType() == typeof(SceneManager));
            thread = new Thread(new ThreadStart(this.Run));
            //thread.IsBackground = true;
            thread.Start();
            base.Initialize();
            
        }
        public void Run()
        {
            ((IsisCubeClient)Game).DisableButtons(null);
            while (!thread.IsAlive);
            IsisSystem.Start(); 
            Msg.RegisterType(typeof(DemoObjectState), (byte)0);
            ((IsisCubeClient)Game).EnableButtons(null);
            IsisSystem.WaitForever();
        }
        public void JoinIsisGroup()
        {
            group = new Group("Isis_Cube_Demo_Node_Group");
            int maxGroupNumber = ((IsisCubeClient)Game).getMaxGroupNumber();
            group.DHTEnable(3, 6, 1);
            group.RegisterViewHandler(new ViewHandler(SetNewView));
            group.Join();
            int id = Math.Abs((view.GetMyRank() * 15) % IsisNode.maxCubeNumber);
            float pos = -SceneManager.planeDistanceFromOrigin + id % (SceneManager.planeDistanceFromOrigin * 2);
            putCube(new Vector3(pos, pos, pos), Vector3.Zero, new Vector3(pos % 1.0f, pos % 1.0f, pos % 1.0f), (int)id, id);
            
        }
        
        private void SetNewView(View v)
        {
            this.view = v;
            

        }

        public void WriteLog()
        {
            IsisSystem.WriteLine(IsisSystem.GetState());
        }

        public IQueryable<KeyValuePair<int, DemoObjectState>> getBalls()
        {
            if (group != null)
                return group.DHT<int, DemoObjectState>().AsQueryable().Where(x => (x.Key) >= maxCubeNumber && (x.Key) < maxBallNumber);
            else
                return null;
        }
        public int getBallCount()
        {
            if (group != null){
                IQueryable<KeyValuePair<int, DemoObjectState>> balls = getBalls();
                return balls.ToList().Count;
            }
            else
                return -1;
        }
        public IQueryable<KeyValuePair<int, DemoObjectState>> getCubes()
        {
            if (group != null)
                return group.DHT<int, DemoObjectState>().AsQueryable().Where(x => (x.Key) >= 0 && (x.Key) < maxCubeNumber);
            else
                return null;
        }
        public Dictionary <int, DemoObjectState> getDemoObjects()
        {
            if (group != null)
                //return group.DHT().ToDictionary(kvp=>(int)kvp.Key,kvp=>(DemoObjectState)kvp.Value);
                return group.DHT().ToDictionary(kvp => (int)kvp.Key, kvp => (DemoObjectState)kvp.Value);
            //return group.DHT<int, DemoObjectState>();
            else
                return null;
        }
        public void putBall(Vector3 position, Vector3 direction, Vector3 color, int number, int id)
        {
            DemoObjectState m = new DemoObjectState(position, direction, color, number, id);
            lock (sceneStateLock)
            {
                if (group != null)
                    group.DHTPut(id, m);
                stateMsgRcvd = true;
                Monitor.Pulse(sceneStateLock);
            }
        }
        public void putCube(Vector3 position, Vector3 direction, Vector3 color, int number, int id)
        {
            DemoObjectState m = new DemoObjectState(position, direction, color, number, id);
            lock (sceneStateLock)
            {
                if (group!=null)
                    group.DHTPut(id, m);
                stateMsgRcvd = true;
                Monitor.Pulse(sceneStateLock);
            }
        }

        
        
    }
}
